#include "Thermostat.h"

#include <WProgram.h>
#include <Metro/Metro.h>
#include <EEPROM/EEPROM.h>
#include <Wire/Wire.h>



Thermostat::Thermostat(Metro *tempSampleTimer, Metro *relayEventTimer) : Observable() {
  EEPROM.read(TARGET_TEMP_ADDR, targetTemp); //pull values out of EEPROM
  targetTemp = constrain(targetTemp, MIN_TARGET_TEMP, MAX_TARGET_TEMP);    
  EEPROM.read(TEMP_RANGE_ADDR, tempRange);
  tempRange = constrain(tempRange, MIN_TEMP_RANGE, MAX_TEMP_RANGE);
  relay = 0;
  this->relayEventTimer = relayEventTimer;

  this->tempSampleTimer = tempSampleTimer;
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, 0);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, 0);
}

void Thermostat::setTargetTemp(float targetTemp) {
  this->targetTemp = targetTemp;
  EEPROM.write(TARGET_TEMP_ADDR, targetTemp);
}

float Thermostat::getTargetTemp() const {
  return this->targetTemp;
}

void Thermostat::setTempRange(float tempRange) {
  this->tempRange = tempRange;
  EEPROM.write(TEMP_RANGE_ADDR, tempRange);
}

float Thermostat::getTempRange() const {
  return this->tempRange;
}

float Thermostat::getTempError() const {
  return this->currentTemp - this->targetTemp;
}

void Thermostat::setRelay(int relay) {
  this->relay = relay;
  if (relay == ON) {
    relayEventTimer->interval(MAX_ON_TIME);
  } 
  else if (relay == OFF) {
    relayEventTimer->interval(MIN_OFF_TIME);
  } 
  digitalWrite(RELAY_PIN, relay);
  digitalWrite(LED_PIN, relay);
}

int Thermostat::getRelay() const {
  return this->relay;
}

float Thermostat::getCurrentTemp() const {
  return currentTemp;
}

void Thermostat::update(Observable *o) {
  if (o == tempSampleTimer) {
    currentTemp = readTemp();
    if (relay == ON) {
      // Leave relay on until temp is tempRange degrees lower than targetTemp or after 1 hour
      if (currentTemp < targetTemp - tempRange || relayEventTimer->check()) { 
        relay = OFF;
        relayEventTimer->interval(MIN_OFF_TIME);
      } //else don't change relay
    } 
    else if (relay == OFF) {
      // Let temperature rise to setTemp + tempRange.  Keep off at least 5 minutes.
      if (currentTemp > targetTemp + tempRange && relayEventTimer->check()) {
        relay = ON;
        relayEventTimer->interval(MAX_ON_TIME);
      }
    }
    digitalWrite(RELAY_PIN, this->relay);
    digitalWrite(LED_PIN, this->relay);
    notifyObservers();
  }
}

float Thermostat::readTemp() {
  int res;
  byte msb;
  byte lsb;
  int val;
  float valf;

  res = Wire.requestFrom(72,2);
  if (res == 2) {
    msb = Wire.receive(); /* Whole degrees */
    lsb = Wire.receive(); /* Fractional degrees */
    val = msb << 8 | lsb; /* MSB */
    valf = val * (0.0625/16);
    return valf*1.8+32;
  }
  else {
    Serial.print("Error Reading Temperature ");
    return 0;
  }
}








